var stats = new Stats(),
    c = document.getElementById('c'),
    ctx = c.getContext('2d');
window.addEventListener('resize', handleWindowResize, false);
function handleWindowResize() {
    c.width = window.innerWidth * window.devicePixelRatio;
    c.height = window.innerHeight * window.devicePixelRatio;
    // rimPosition.x = c.width - 310;
}
handleWindowResize();

//记录鼠标位置
var mouse = new Vector(0, 0),
    isMouseDown = false,
    isEnterBall = false,
    frameAnimationId = '',
    ARENA_LENGTH_IN_METER = 10, //将canvas宽度看做10米,
    pixelsPerMeter = c.width / ARENA_LENGTH_IN_METER, //没米的像素数
    fps = 60, //默认fps
    calculationParameters = {
        power: 0, //初始力，单位 N
        angle: 0, //力、速度的角度（方向）
        InitVelocity: 0, //初速度
        lastTime: 0, //上一次次计算时间
        GRAVITY_FORCE: 9.81, //重力加速度
        score: 0, //得分
        intersectionPoint: { //光线投射法碰撞检测的交叉点
            x: 0,
            y: 0
        }
    },
    rimPosition = {
        x: c.width - 310,
        y: 750,
        width: 120,
        height: 10,
        leftPoint: { x: c.width - 310, y: 750 },
        rightPoint: { x: c.width - 310 + 120, y: 750 }
    };

function Ball (x, y, r) {
    Vector.call(this, x, y);
    this.r = r || 20;
    this.speed = new Vector();
    this.MASS = .1; //物理质量，单位：KG
    this.vx0 = 0;
    this.vy0 = 0;
    this.lob = false;
    //光线透射碰撞检测-光线直线斜截式函数 参数
    this.lastBallPostion = { x: 0, y: 0 };
    this.a = 0;
    this.b = 0;
} 
Ball.prototype = (function (o) {
    var v = new Vector(0, 0);
    for(var p in o) {
        v[p] = o[p];
    }
    return v;
})({
    update: function (ctx) {
        if(this.lob) {
            this.lastBallPostion.x = this.x;
            this.lastBallPostion.y = this.y;
            var time = +new Date();
            this.speed.set({
                // 这一帧的速度由两部分构成： 在某一加速度下，此一帧是某速度时，应移动的像素数 + 初速度下应移动的像素数 
                x: pixelsPerMeter * ((time - calculationParameters.lastTime) / 1000) * 0 / fps + this.vx0 * pixelsPerMeter / fps,
                y: pixelsPerMeter * ((time - calculationParameters.lastTime) / 1000) * calculationParameters.GRAVITY_FORCE / fps + this.vy0 * pixelsPerMeter / fps
            })
            this.x += this.speed.x;
            this.y += this.speed.y;
        }
        if(this.hitTest(ctx)) {
            calculationParameters.score += 1;
            this.reset();
        } else {
            if(this.x + this.r >= c.width) {
                this.reset();
            } else if (this.x - this.r <= 0) {
                this.reset();
            }
            if(this.y + this.r >= c.height) {
                this.reset();
            } else if (this.y - this.r <= 0) {
                this.reset();
            }
        }
        this.draw(ctx);
        this.drawRim(ctx);
        this.drawScore(ctx);
    },
    draw: function (ctx) {
        ctx.save();
        ctx.fillStyle =  'red';
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
        ctx.closePath();
        ctx.fill();
        ctx.restore();
    },
    drawRay: function (ctx) {
        if(this.a !== 0) {
            var point1 = { x: 0, y: this.b };
            var point2;
            if(this.a <= 0) {
                point2 = { x: -1 * this.b / this.a, y: 0 };
            } else {
                point2 = { x: c.width, y: this.a * c.width + this.b };
            }
            ctx.save();
            ctx.strokeStyle = 'black';
            ctx.lineWidth = 1;
            ctx.beginPath();
            ctx.moveTo(point1.x, point1.y);
            ctx.lineTo(point2.x, point2.y);
            ctx.stroke();
            ctx.restore();
        }
    },
    drawLine: function (ctx) {
        ctx.save();
        ctx.strokeStyle = '#333';
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.moveTo(this.x, this.y);
        ctx.lineTo(mouse.x, mouse.y);
        ctx.closePath();
        ctx.stroke();
        ctx.restore();
    },
    drawText: function (ctx) {
        ctx.save();
        ctx.fillStyel = 'black';
        ctx.font = '16px 微软雅黑';
        ctx.fillText('F：' + calculationParameters.power + 'N', 20, 50);
        ctx.fillText('v:' + calculationParameters.InitVelocity + 'M/s', 20, 80);
        ctx.fillText('arc:' + calculationParameters.angle + 'rad', 20, 110);
        ctx.fillText('a:' + this.a + '--' + 'b:' + this.b, 20, 140);
        ctx.restore();
    },
    drawScore: function (ctx) {
        ctx.save();
        ctx.fillStyle = 'blue';
        ctx.font = '26px 微软雅黑';
        ctx.textAlign = 'center';
        ctx.textBaseLine = 'middle';
        ctx.fillText(calculationParameters.score, c.width / 2, 100);
        ctx.restore();
    },
    reset: function () {
        this.set(200, 750);
        this.speed.set(0, 0);
        this.vx0 = 0;
        this.vy0 = 0;
        this.lob = false;
        this.a = 0;
        this.b = 0;
    },
    drawRim: function (ctx) {
        ctx.save();
        ctx.fillStyle = 'black';
        ctx.strokeStyle = 'black';
        ctx.lineWidth = 1;
        ctx.fillRect(rimPosition.x, rimPosition.y, rimPosition.width, rimPosition.height);

        ctx.save();
        ctx.fillStyle = 'blue';
        ctx.beginPath();
        ctx.arc(rimPosition.leftPoint.x, rimPosition.leftPoint.y, 4, 0, Math.PI * 2);
        ctx.arc(rimPosition.rightPoint.x, rimPosition.rightPoint.y, 4, 0, Math.PI * 2);
        ctx.arc(calculationParameters.intersectionPoint.x, calculationParameters.intersectionPoint.y, 8, 0, Math.PI * 2);
        ctx.closePath();
        ctx.fill();
        ctx.restore();

        ctx.beginPath();
        ctx.moveTo(c.width, rimPosition.y);
        ctx.lineTo(0, rimPosition.y);
        ctx.stroke();
        ctx.restore();
    },
    hitTest: function (ctx) {
        //以下为光线投射法碰撞检测的具体代码
        var x1 = this.lastBallPostion.x,
            y1 = this.lastBallPostion.y,
            x2 = rimPosition.leftPoint.x,
            y2 = rimPosition.leftPoint.y,
            x3 = rimPosition.rightPoint.x,
            y3 = rimPosition.rightPoint.y,
            m2 = (y3 - y2) / (x3 - x2),
            b2 = y2 - m2 * x2;
            this.a = (this.y - this.lastBallPostion.y) / (this.x - this.lastBallPostion.x);
            this.b = y1 - this.a * x1;
        calculationParameters.intersectionPoint.x = (b2 - this.b) / (this.a - m2);
        calculationParameters.intersectionPoint.y = this.a * calculationParameters.intersectionPoint.x + this.b;
        this.drawRay(ctx);
        return calculationParameters.intersectionPoint.x > x2 &&
               calculationParameters.intersectionPoint.x < x3 &&
               this.y + this.r > y2 &&
               this.x + this.r < x3;
    }
});

var ball = new Ball(200, 750);

(function bindEvent () {
    //鼠标运动事件
    document.addEventListener('mousemove', hansleDosMouseMove, false);
    //鼠标按下事件
    c.addEventListener('mousedown', handleCMouseDown, false);
    document.addEventListener('mouseup', handleDomMouseUp, false);

    function hansleDosMouseMove (e) {
        if(!ball.lob) {
            mouse.set({
                x: e.clientX,
                y: e.clientY
            });
            var distance = ball.modeTo(mouse);
            calculationParameters.power = getPowerFromDis(distance);
            calculationParameters.angle = ball.angleTo(mouse);
            calculationParameters.InitVelocity = (calculationParameters.power * (1 / 60) / ball.MASS);
            if(distance < ball.r) {
                isEnterBall = true;
                c.style.cursor = 'pointer';
            } else {
                if(!isMouseDown) {
                    isEnterBall = false;
                    c.style.cursor = 'default';
                }
            }
        }
    }

    function handleCMouseDown (e) {
        if(isEnterBall) {
            isMouseDown = true;
            isEnterBall = true;
        }
    }

    function handleDomMouseUp (e) {
        if(isMouseDown && isEnterBall) {
            isMouseDown = false;
            isEnterBall = false;
            calculationParameters.lastTime = +new Date();
            var tempVx = calculationParameters.InitVelocity * Math.cos(calculationParameters.angle);
            var tempVy = calculationParameters.InitVelocity * Math.sin(calculationParameters.angle)
            ball.speed.set({
                x: tempVx,
                y: tempVy
            })
            ball.vx0 = tempVx;
            ball.vy0 = tempVy;
            ball.lob = true;
            c.style.cursor = 'default';
        }
    }

    function getPowerFromDis (dis) {
        var temp = Math.ceil(dis / 10);
        return temp;
    }
}());

(function loop (time) {
    ctx.clearRect(0, 0, c.width, c.height);
    requestAnimationFrame(loop);
    var tempFps = stats.update();
    fps = tempFps === 0 ? 60 : tempFps;
    ball.update(ctx);
    if(isMouseDown) {
        ball.drawLine(ctx);
        ball.drawText(ctx);
    }
}());